/**
 * @file      : queue.h
 * @brief     : 队列驱动头文件
 * @author    : huenrong (huenrong1028@gmail.com)
 * @date      : 2021-04-10 15:21:00
 *
 * @copyright : Copyright (c) 2021  胡恩荣
 *
 */

#ifndef __QUEUE_H
#define __QUEUE_H

#include <stdint.h>
#include <pthread.h>

// 循环队列结构体
struct queue
{
    uint8_t *data;               // 指向缓冲区的指针
    uint32_t head;               // 队列头指针(指向队列头元素)
    uint32_t tail;               // 队列尾指针(指向队列尾元素的下一个位置)
    uint32_t total_size;         // 队列缓冲区的总大小
    uint32_t current_size;       // 队列当前大小
    pthread_mutex_t queue_mutex; // 队列互斥锁
    pthread_cond_t queue_cond;   // 队列条件变量
};

/**
 * @brief  初始化循环队列
 * @param  queue_name: 输出参数, 队列名
 * @param  queue_size: 输入参数, 队列缓冲区的总大小
 * @return 成功: 0
 *         失败: -1
 */
int init_queue(struct queue *queue_name, const uint32_t queue_size);

/**
 * @brief  清空循环队列
 * @param  queue_name: 输出参数, 队列名
 */
void clear_queue(struct queue *queue_name);

/**
 * @brief  获取队列元素的个数
 * @param  queue_name: 输入参数, 队列名
 * @return 队列元素的个数
 */
uint32_t get_queue_length(struct queue queue_name);

/**
 * @brief  插入数据到循环队列
 * @param  queue_name: 输出参数, 队列名
 * @param  data      : 输入参数, 需要插入的数据
 * @param  data_len  : 输入参数, 需要插入的数据长度
 * @return 实际插入的个数
 */
uint32_t insert_queue(struct queue *queue_name, const uint8_t *data,
                      const uint32_t data_len);

/**
 * @brief  阻塞方式从循环队列中获取数据
 * @param  queue_name: 输出参数, 队列名
 * @param  data      : 输出参数, 获取到的数据
 * @param  data_len  : 输入参数, 指定获取长度
 * @return 实际获取的个数
 */
uint32_t get_queue(struct queue *queue_name, uint8_t *data,
                   const uint32_t data_len);

/**
 * @brief  超时方式从循环队列中获取数据(超时时间为0, 直接从队列获取数据)
 * @param  queue_name: 输出参数, 队列名
 * @param  data      : 输出参数, 获取到的数据
 * @param  data_len  : 输入参数, 指定获取长度
 * @param  timeout   : 输入参数, 超时时间(单位: ms)
 * @return 超时: -1
 *         其它: 实际获取的个数
 */
int get_queue_with_timeout(struct queue *queue_name, uint8_t *data,
                           const uint32_t data_len, const uint32_t timeout);

/**
 * @brief  判断循环队列是否为空
 * @param  queue_name: 输入参数, 队列名
 * @return 0: 队列非空
 *         1: 队列为空
 */
int queue_is_empty(const struct queue queue_name);

/**
 * @brief  销毁队列
 * @param  queue_name: 输出参数, 队列名
 * @return 成功: 0
 *         失败: -1
 */
int queue_destroy(struct queue *queue_name);

#endif // __QUEUE_H
